/* 
  封装一个jsonp方法「基于promise管理」,执行这个方法可以发送jsonp请求 
    jsonp([url],[options])
      options配置项
      + params:null/对象 问号参数信息
      + jsonpName:'callback' 基于哪个字段把全局函数名传递给服务器
      + ...
*/
(function () {
	//是不纯对象
  const isPlainObject = function isPlainObject(obj) {
    let proto, Ctor;
    if (!obj || Object.prototype.toString.call(obj) !== "[object Object]") return false;
    proto = Object.getPrototypeOf(obj);
    if (!proto) return true;
    Ctor = proto.hasOwnProperty('constructor') && proto.constructor;
    return typeof Ctor === "function" && Ctor === Object;
  };

//将纯对象--》urlencoded格式
  const stringify = function stringify(obj) {
    let keys = Reflect.ownKeys(obj),
      str = ``;
    keys.forEach(key => {
      str += `&${key}=${obj[key]}`;
    });
    return str.substring(1);
  };

  const jsonp = function jsonp(url, options) {
	 //url 必须字符串，而且必须填写
     if(typeof url!=="string"){
		 throw new TypeError("url must be required!")
	 }
	 //options 不是个纯对象，就让它等于纯对象
	 if(!isPlainObject(options)){
		 options={}
	 }
	 
	 //options的合并
	 options=Object.assign({
		 params:null,
		 jsonpName:'callback'
	 },options)
	 
	 //返回promise实例，才能使用 .then .catch
	 return new Promise((resolve,reject)=>{
		 let {params,jsonpName}=options;
		 
		 if(params){
			 //如果params 是纯对象，就转换为 urlencoded
			if(isPlainObject(params)){
				params=stringify(params);
				//url 如果有问号，就用&拼，如果有没问号，就用?拼
				url+=`${url.includes("?") ? "&":"?"}${params}`
			}
		 }
		 
		 //最后，删除script标签，还有window上添加的函数名
		 const clear=function clear(){
			 
		 	let myscript=document.querySelector("#myscript");
			document.body.removeChild(myscript);
			
			delete window[funName];
		 }
		 
		//永远不会重复的函数名
		let funName=`funName${+new Date()}`
		window[funName]=function(value){//获取成功，返回成功的值
			resolve(value);
			clear();
		}
		 
		url+=`${url.includes("?") ? "&":"?"}${jsonpName}=${funName}`
		 
		
		//创建 srcipt 标签，写入到页面
		let script=document.createElement("script");
		script.src=url;//"http://127.0.0.1:1001/user/list?callback=funcc"
		script.id="myscript";
		script.onerror=function(err){//请求失败，返回失败值
			reject(err);
			clear();+
		}
		document.body.appendChild(script);
	 })
	 
  };

  /* 暴露API */
  if (typeof module === 'object' && typeof module.exports === 'object') module.exports = jsonp;
  if (typeof window !== 'undefined') window.jsonp = jsonp;
})();